package com.jeesite.modules.dataScreen.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeesite.modules.dataScreen.constants.CacheConstants;
import com.jeesite.modules.dataScreen.dao.IndustryIndexDao;
import com.jeesite.modules.dataScreen.dao.WaybillDao;
import com.jeesite.modules.dataScreen.web.dto.IndustryIndexParam;
import com.jeesite.modules.dataScreen.web.vo.IndustryIndexVo;
import com.jeesite.modules.dataScreen.web.vo.electronic.*;
import lombok.val;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 安全应急相关
 */
@Service
public class WaybillService {

    //10分钟
    private static final long DS_DELAY = 600000;

    @Resource
    private WaybillDao waybillDao;

    @Resource
    private IndustryIndexService industryIndexService;

    Map<String, Object> cacheMap = new ConcurrentHashMap<>(16);

    //电子运单
    public List<ElectronicTransVo> electronicTrans() {
        Object electronicTrans = cacheMap.get("electronicTrans");
        if (Objects.nonNull(electronicTrans)) {
            return (List<ElectronicTransVo>) electronicTrans;
        }
        return refElectronicTrans();
    }

    @Scheduled(fixedDelay = DS_DELAY)
    public List<ElectronicTransVo> refElectronicTrans() {
        List<ElectronicTransVo> electronicTransVos = doElectronicTrans();
        cacheMap.put("electronicTrans", electronicTransVos);
        return electronicTransVos;
    }

    public List<ElectronicTransVo> doElectronicTrans() {
        List<ElectronicTransVo> transVos = new ArrayList<>();
        Map<String, JSONObject> comtMap = waybillDao.getDzys(DateUtil.beginOfYear(DateUtil.date()),
                DateUtil.endOfYear(DateUtil.date()), 6);
        Map<String, JSONObject> allMap = waybillDao.getDzys(DateUtil.beginOfYear(DateUtil.date()),
                DateUtil.endOfYear(DateUtil.date()), null);

        Map<String, String> datedStr = dateStr();
        ElectronicTransVo vo;
        for (Map.Entry<String, String> entry : datedStr.entrySet()) {
            vo = new ElectronicTransVo();
            vo.setMonth(entry.getKey());
            JSONObject jsonObject = comtMap.get(entry.getValue());
            if (jsonObject != null) {
                vo.setFinish(jsonObject.getIntValue("val"));
            }
            jsonObject = allMap.get(entry.getValue());
            if (jsonObject != null) {
                vo.setTotal(jsonObject.getIntValue("val"));
            }
            transVos.add(vo);
        }
        return transVos;
    }

    public List<String> county() {
        Object object = cacheMap.get("waybill:county");
        if (Objects.nonNull(object)) {
            return (List<String>) object;
        }
        return refCounty();
    }

    private List<String> refCounty() {
        List<String> strings = doCounty();
        cacheMap.put("waybill:county", strings);
        return strings;
    }

    public List<String> doCounty() {

        return waybillDao.county();
    }

    private Map<String, String> dateStr() {
        DateTime startTime = DateUtil.beginOfYear(DateUtil.date());
        String pattern = "yyyy-MM";
        String endTime = DateUtil.format(DateUtil.date(), pattern);
        Map<String, String> map = new HashMap<>();
        String tem;
        do {
            tem = DateUtil.format(startTime, pattern);
            map.put(StrUtil.format("{}月", startTime.getMonth() + 1), tem);
            startTime = DateUtil.offsetMonth(startTime, 1);
        }
        while (!StrUtil.equals(tem, endTime));
        return map;
    }

    public CountyCheckVo countyCheck(String county) {
        Object object = cacheMap.get(countyCheckCacheKey(county));
        if (Objects.nonNull(object)) {
            return (CountyCheckVo) object;
        }
        return refCountyCheck(CollUtil.toList(county)).get(county);
    }

    private Map<String, CountyCheckVo> refCountyCheck(List<String> countys) {
        Map<String, CountyCheckVo> countyCheckMap = doCountyCheck(countys);
        for (Map.Entry<String, CountyCheckVo> entry : countyCheckMap.entrySet()) {
            cacheMap.put(countyCheckCacheKey(entry.getKey()), entry.getValue());
        }
        return countyCheckMap;
    }

    @Scheduled(fixedDelay = DS_DELAY)
    public void refCountyCheck() {
        List<String> countys = refCounty();
        refCountyCheck(countys);
    }

    private String countyCheckCacheKey(String county) {
        return "countyCheck_" + county;
    }


    public Map<String, CountyCheckVo> doCountyCheck(List<String> countys) {
        Map<String, CountyCheckVo> resultMap = new HashMap<>(countys.size());

        Map<String, JSONObject> countyMap = waybillDao.countyCheck(countys);
        if (Objects.isNull(countyMap)) {
            return resultMap;
        }
        for (Map.Entry<String, JSONObject> entry : countyMap.entrySet()) {
            CountyCheckVo checkVo = new CountyCheckVo();
            JSONObject result = entry.getValue();
            int verify = result.getIntValue("verify");
            int loadAll = result.getIntValue("loadall");
            int verifyOk = result.getIntValue("verifyok");
            if (loadAll > 0) {
                checkVo.setCheckRatio(BigDecimal.valueOf(verify * 100L).divide(BigDecimal.valueOf(loadAll), BigDecimal.ROUND_DOWN, RoundingMode.UP));
            }
            if (verify > 0) {
                checkVo.setCheckPassRatio(BigDecimal.valueOf(verifyOk * 100L).divide(BigDecimal.valueOf(verify), BigDecimal.ROUND_DOWN, RoundingMode.UP));
            }
            resultMap.put(entry.getKey(), checkVo);
        }

        return resultMap;
    }

    public ElectronicCenterVo centerTitle() {
        return waybillDao.centerTitle();
    }

    public List<OwnerGwVo> ownerGw() {
        return waybillDao.ownerGw();
    }

    /**
     * 高危企业弹窗
     *
     * @param pageNum
     * @param pageSize
     * @param areName  地区名称
     * @return
     */
    public IPage<OwnerGwViewVo> ownerGwView(Integer pageNum, Integer pageSize, String areName) {
        IPage<OwnerGwViewVo> gwView = new Page<>();
        gwView.setCurrent(pageNum);
        gwView.setSize(pageSize);
        return waybillDao.ownerGwView(gwView, areName);
    }

    //年度安全隐患
    public JSONObject companyTrouble() {
        List<CompanyTroubleVo> companyTrouble = waybillDao.getCompanyTrouble(DateUtil.beginOfYear(DateUtil.date()));
        JSONObject result = new JSONObject();

        int trouble = companyTrouble.stream().mapToInt(CompanyTroubleVo::getTrouble).sum();
        int troubletgs = companyTrouble.stream().mapToInt(CompanyTroubleVo::getTroubletgs).sum();
        result.put("trouble", trouble);
        BigDecimal ratio = BigDecimal.ZERO;
        if (troubletgs > 0) {
            ratio = BigDecimal.valueOf(troubletgs * 100L).divide(BigDecimal.valueOf(trouble), BigDecimal.ROUND_UP, RoundingMode.UP);
        }
        result.put("ratio", ratio);
        companyTrouble.sort(Comparator.comparing(CompanyTroubleVo::getName));
        result.put("months", companyTrouble);
        return result;
    }

    public IPage<CompanyTroubleViewVo> companyTroubleView(Integer pageNum, Integer pageSize, Integer monthVal) {
        IPage<CompanyTroubleViewVo> gwView = new Page<>();
        gwView.setCurrent(pageNum);
        gwView.setSize(pageSize);
        DateTime dateTime = DateUtil.date().setField(DateField.MONTH, Math.max(monthVal - 1, 0));
        return waybillDao.getCompanyTroubleView(gwView, DateUtil.beginOfMonth(dateTime), DateUtil.endOfMonth(dateTime));
    }

    public IPage<TroubleDlYhVo> dlTrouble(Integer pageNum, Integer pageSize) {
        IPage<TroubleDlYhVo> gwView = new Page<>();
        gwView.setCurrent(pageNum);
        gwView.setSize(pageSize);
        return waybillDao.getDlTrouble(gwView);
    }

    public JSONObject doubleLuTrouble() {
        IPage<TroubleDoubleVo> gwView = new Page<>();
        gwView.setCurrent(1);
        gwView.setSize(Integer.MAX_VALUE);
        JSONObject result = new JSONObject();
        IPage<TroubleDoubleVo> page = waybillDao.getDoubleLuTrouble(gwView);
        result.put("onlineCarNum", waybillDao.onlineCarNum());
        result.put("datas", page.getRecords());
        return result;
    }

    public TroubleSecureVo troubleSecure() {
        Map<String, IndustryIndexVo> indexVoMap = industryIndexService.getUnRealtime("航道流量（北碚三）", "航道流量（寸滩）"
                , "航道流量（武隆）", "能见度（嘉陵江）", "船舶滞留数");
        TroubleSecureVo result = new TroubleSecureVo();
        result.setBbFlow(indexVoMap.get("航道流量（北碚三）"));
        result.setWlFlow(indexVoMap.get("航道流量（武隆）"));
        result.setCtFlow(indexVoMap.get("航道流量（寸滩）"));
        result.setNjd(indexVoMap.get("能见度（嘉陵江）"));
        result.setCbzls(indexVoMap.get("船舶滞留数"));

        indexVoMap = industryIndexService.getRealtime("航道水位（武隆）", "航道水位（寸滩）", "航道水位（北碚三）");
        result.setCtLevel(indexVoMap.get("航道水位（寸滩）"));
        result.setBbLevel(indexVoMap.get("航道水位（北碚三）"));
        result.setWlLevel(indexVoMap.get("航道水位（武隆）"));
        return result;
    }

    public UnloadAndTransportVo unloadAndTransport() {
        UnloadAndTransportVo result = new UnloadAndTransportVo();

        Map<String, IndustryIndexVo> indexVoMap = industryIndexService.getUnRealtime("重庆市当前道路危货运输超速驾驶线索数", "重庆市当前道路危货运输疲劳驾驶线索数"
                , "全市当前道路危货运输西部陆海新通道货运量比率", "重庆市当前道路危货运输货物总量",
                "重庆市当前道路危货运输脱管车辆数", "重庆市当日道路危货运输车辆脱管率");
        result.setCsjs(indexVoMap.get("重庆市当前道路危货运输超速驾驶线索数"));
        result.setPljs(indexVoMap.get("重庆市当前道路危货运输疲劳驾驶线索数"));
        result.setHylRate(indexVoMap.get("全市当前道路危货运输西部陆海新通道货运量比率"));
        result.setHwTotal(indexVoMap.get("重庆市当前道路危货运输货物总量"));
        result.setTgCar(indexVoMap.get("重庆市当前道路危货运输脱管车辆数"));
        result.setTgCarRate(indexVoMap.get("重庆市当日道路危货运输车辆脱管率"));
        indexVoMap = industryIndexService.getRealtime("重庆市实时道路危货运输在线车辆数", "重庆市当前道路危货运输电子运单总数",
                "全市当前道路危货运输电子运单校验合格率", "重庆市当前道路危货装载未查验数", "重庆市当前道路危货装载已查验数");

        result.setOnlineCar(indexVoMap.get("重庆市实时道路危货运输在线车辆数"));
        result.setDzydTotal(indexVoMap.get("重庆市当前道路危货运输电子运单总数"));
        result.setDzydCheckRate(indexVoMap.get("全市当前道路危货运输电子运单校验合格率"));
        result.setZzUnCheck(indexVoMap.get("重庆市当前道路危货装载未查验数"));
        result.setZzCheck(indexVoMap.get("重庆市当前道路危货装载已查验数"));
        return result;
    }

    public SecurityRiskVo securityRisk(boolean realtime) {
        return realtime ? securityRiskRealtime() : securityRiskMonth();
    }

    private SecurityRiskVo securityRiskMonth() {
        Map<String, IndustryIndexVo> indexVoMap = industryIndexService.getUnRealtime("重庆市月度道路危货运输驾驶员健康度", "重庆市月度道路危货运输高风险驾驶员比率",
                "重庆市月度道路危货运输车辆健康度", "全市当前道路危货运输群众好评率",
                "重庆市月度道路危货运输车辆健康度", "重庆市月度道路危货运输高风险车辆比率",
                "重庆市月度道路危货运输高风险企业比率", "重庆市月度道路危货运输企业健康度");
        SecurityRiskVo result = new SecurityRiskVo();
        result.setHealth(indexVoMap.get("重庆市月度道路危货运输驾驶员健康度"));
        result.setRisk(indexVoMap.get("重庆市月度道路危货运输高风险驾驶员比率"));
        result.setCarHealth(indexVoMap.get("重庆市月度道路危货运输车辆健康度"));
        result.setCarRisk(indexVoMap.get("重庆市月度道路危货运输高风险车辆比率"));
        result.setCompanyHealth(indexVoMap.get("重庆市月度道路危货运输企业健康度"));
        result.setCompanyRisk(indexVoMap.get("重庆市月度道路危货运输高风险企业比率"));
        result.setEvaluate(indexVoMap.get("全市当前道路危货运输群众好评率"));
        return result;
    }

    private SecurityRiskVo securityRiskRealtime() {
        Map<String, IndustryIndexVo> indexVoMap = industryIndexService.getRealtime("全市实时道路危货运输驾驶员健康度", "全市实时道路危货运输高风险驾驶员比率",
                "全市实时道路危货运输车辆健康度",
                "全市实时道路危货运输车辆健康度", "全市实时道路危货运输高风险车辆比率",
                "全市实时道路危货运输高风险企业比率", "全市实时道路危货运输企业健康度");
        SecurityRiskVo result = new SecurityRiskVo();
        result.setHealth(indexVoMap.get("全市实时道路危货运输驾驶员健康度"));
        result.setRisk(indexVoMap.get("全市实时道路危货运输高风险驾驶员比率"));
        result.setCarHealth(indexVoMap.get("全市实时道路危货运输车辆健康度"));
        result.setCarRisk(indexVoMap.get("全市实时道路危货运输高风险车辆比率"));
        result.setCompanyHealth(indexVoMap.get("全市实时道路危货运输企业健康度"));
        result.setCompanyRisk(indexVoMap.get("全市实时道路危货运输高风险企业比率"));
        return result;
    }
}
